using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization;

namespace HalconDotNet
{
	[Serializable]
	public class HObject : HObjectBase, ISerializable, ICloneable
	{
		public HObject this[HTuple index] => SelectObj(index);

		public HObject()
			: base(HObjectBase.UNDEF, copy: false)
		{
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		public HObject(IntPtr key)
			: this(key, copy: true)
		{
			AssertObjectClass();
			GC.KeepAlive(this);
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		public HObject(IntPtr key, bool copy)
			: base(key, copy)
		{
			AssertObjectClass();
			GC.KeepAlive(this);
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		public HObject(HObject obj)
			: base(obj)
		{
			AssertObjectClass();
			GC.KeepAlive(this);
		}

		private void AssertObjectClass()
		{
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		public static int LoadNew(IntPtr proc, int parIndex, int err, out HObject obj)
		{
			obj = new HObject(HObjectBase.UNDEF);
			return obj.Load(proc, parIndex, err);
		}

		void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
		{
			HSerializedItem hSerializedItem = SerializeObject();
			byte[] value = hSerializedItem;
			hSerializedItem.Dispose();
			info.AddValue("data", value, typeof(byte[]));
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		public HObject(SerializationInfo info, StreamingContext context)
		{
			byte[] data = (byte[])info.GetValue("data", typeof(byte[]));
			HSerializedItem hSerializedItem = new HSerializedItem(data);
			DeserializeObject(hSerializedItem);
			hSerializedItem.Dispose();
		}

		public void Serialize(Stream stream)
		{
			HSerializedItem hSerializedItem = SerializeObject();
			hSerializedItem.Serialize(stream);
			hSerializedItem.Dispose();
		}

		public static HObject Deserialize(Stream stream)
		{
			HObject hObject = new HObject();
			HSerializedItem hSerializedItem = HSerializedItem.Deserialize(stream);
			hObject.DeserializeObject(hSerializedItem);
			hSerializedItem.Dispose();
			return hObject;
		}

		object ICloneable.Clone()
		{
			return Clone();
		}

		public HObject Clone()
		{
			HSerializedItem hSerializedItem = SerializeObject();
			HObject hObject = new HObject();
			hObject.DeserializeObject(hSerializedItem);
			hSerializedItem.Dispose();
			return hObject;
		}

		public HObject ObjDiff(HObject objectsSub)
		{
			IntPtr proc = HalconAPI.PreCall(573);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objectsSub);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objectsSub);
			return obj;
		}

		public void IntegerToObj(HTuple surrogateTuple)
		{
			Dispose();
			IntPtr proc = HalconAPI.PreCall(581);
			HalconAPI.Store(proc, 0, surrogateTuple);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			HalconAPI.UnpinTuple(surrogateTuple);
			err = Load(proc, 1, err);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
		}

		public void IntegerToObj(IntPtr surrogateTuple)
		{
			Dispose();
			IntPtr proc = HalconAPI.PreCall(581);
			HalconAPI.StoreIP(proc, 0, surrogateTuple);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = Load(proc, 1, err);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
		}

		public HTuple ObjToInteger(int index, int number)
		{
			IntPtr proc = HalconAPI.PreCall(582);
			Store(proc, 1);
			HalconAPI.StoreI(proc, 0, index);
			HalconAPI.StoreI(proc, 1, number);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			err = HTuple.LoadNew(proc, 0, HTupleType.INTEGER, err, out HTuple tuple);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return tuple;
		}

		public HObject CopyObj(int index, int numObj)
		{
			IntPtr proc = HalconAPI.PreCall(583);
			Store(proc, 1);
			HalconAPI.StoreI(proc, 0, index);
			HalconAPI.StoreI(proc, 1, numObj);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return obj;
		}

		public HObject ConcatObj(HObject objects2)
		{
			IntPtr proc = HalconAPI.PreCall(584);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objects2);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objects2);
			return obj;
		}

		public HObject SelectObj(HTuple index)
		{
			IntPtr proc = HalconAPI.PreCall(587);
			Store(proc, 1);
			HalconAPI.Store(proc, 0, index);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			HalconAPI.UnpinTuple(index);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return obj;
		}

		public HObject SelectObj(int index)
		{
			IntPtr proc = HalconAPI.PreCall(587);
			Store(proc, 1);
			HalconAPI.StoreI(proc, 0, index);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return obj;
		}

		public int CompareObj(HObject objects2, HTuple epsilon)
		{
			IntPtr proc = HalconAPI.PreCall(588);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objects2);
			HalconAPI.Store(proc, 0, epsilon);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			HalconAPI.UnpinTuple(epsilon);
			err = HalconAPI.LoadI(proc, 0, err, out int intValue);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objects2);
			return intValue;
		}

		public int CompareObj(HObject objects2, double epsilon)
		{
			IntPtr proc = HalconAPI.PreCall(588);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objects2);
			HalconAPI.StoreD(proc, 0, epsilon);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			err = HalconAPI.LoadI(proc, 0, err, out int intValue);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objects2);
			return intValue;
		}

		public int TestEqualObj(HObject objects2)
		{
			IntPtr proc = HalconAPI.PreCall(591);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objects2);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			err = HalconAPI.LoadI(proc, 0, err, out int intValue);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objects2);
			return intValue;
		}

		public int CountObj()
		{
			IntPtr proc = HalconAPI.PreCall(592);
			Store(proc, 1);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			err = HalconAPI.LoadI(proc, 0, err, out int intValue);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return intValue;
		}

		public HTuple GetChannelInfo(string request, HTuple channel)
		{
			IntPtr proc = HalconAPI.PreCall(593);
			Store(proc, 1);
			HalconAPI.StoreS(proc, 0, request);
			HalconAPI.Store(proc, 1, channel);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			HalconAPI.UnpinTuple(channel);
			err = HTuple.LoadNew(proc, 0, err, out HTuple tuple);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return tuple;
		}

		public string GetChannelInfo(string request, int channel)
		{
			IntPtr proc = HalconAPI.PreCall(593);
			Store(proc, 1);
			HalconAPI.StoreS(proc, 0, request);
			HalconAPI.StoreI(proc, 1, channel);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			err = HalconAPI.LoadS(proc, 0, err, out string stringValue);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return stringValue;
		}

		public HTuple GetObjClass()
		{
			IntPtr proc = HalconAPI.PreCall(594);
			Store(proc, 1);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			err = HTuple.LoadNew(proc, 0, err, out HTuple tuple);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return tuple;
		}

		public void GenEmptyObj()
		{
			Dispose();
			IntPtr proc = HalconAPI.PreCall(617);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = Load(proc, 1, err);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
		}

		public void DispObj(HWindow windowHandle)
		{
			IntPtr proc = HalconAPI.PreCall(1276);
			Store(proc, 1);
			HalconAPI.Store(proc, 0, windowHandle);
			int procResult = HalconAPI.CallProcedure(proc);
			HalconAPI.PostCall(proc, procResult);
			GC.KeepAlive(this);
			GC.KeepAlive(windowHandle);
		}

		public void ReadObject(string fileName)
		{
			Dispose();
			IntPtr proc = HalconAPI.PreCall(1646);
			HalconAPI.StoreS(proc, 0, fileName);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = Load(proc, 1, err);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
		}

		public void WriteObject(string fileName)
		{
			IntPtr proc = HalconAPI.PreCall(1647);
			Store(proc, 1);
			HalconAPI.StoreS(proc, 0, fileName);
			int procResult = HalconAPI.CallProcedure(proc);
			HalconAPI.PostCall(proc, procResult);
			GC.KeepAlive(this);
		}

		public void DeserializeObject(HSerializedItem serializedItemHandle)
		{
			Dispose();
			IntPtr proc = HalconAPI.PreCall(1648);
			HalconAPI.Store(proc, 0, serializedItemHandle);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = Load(proc, 1, err);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(serializedItemHandle);
		}

		public HSerializedItem SerializeObject()
		{
			IntPtr proc = HalconAPI.PreCall(1649);
			Store(proc, 1);
			HalconAPI.InitOCT(proc, 0);
			int err = HalconAPI.CallProcedure(proc);
			err = HSerializedItem.LoadNew(proc, 0, err, out HSerializedItem obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return obj;
		}

		public HObject InsertObj(HObject objectsInsert, int index)
		{
			IntPtr proc = HalconAPI.PreCall(2121);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objectsInsert);
			HalconAPI.StoreI(proc, 0, index);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objectsInsert);
			return obj;
		}

		public HObject RemoveObj(HTuple index)
		{
			IntPtr proc = HalconAPI.PreCall(2124);
			Store(proc, 1);
			HalconAPI.Store(proc, 0, index);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			HalconAPI.UnpinTuple(index);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return obj;
		}

		public HObject RemoveObj(int index)
		{
			IntPtr proc = HalconAPI.PreCall(2124);
			Store(proc, 1);
			HalconAPI.StoreI(proc, 0, index);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			return obj;
		}

		public HObject ReplaceObj(HObject objectsReplace, HTuple index)
		{
			IntPtr proc = HalconAPI.PreCall(2125);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objectsReplace);
			HalconAPI.Store(proc, 0, index);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			HalconAPI.UnpinTuple(index);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objectsReplace);
			return obj;
		}

		public HObject ReplaceObj(HObject objectsReplace, int index)
		{
			IntPtr proc = HalconAPI.PreCall(2125);
			Store(proc, 1);
			HalconAPI.Store(proc, 2, objectsReplace);
			HalconAPI.StoreI(proc, 0, index);
			HalconAPI.InitOCT(proc, 1);
			int err = HalconAPI.CallProcedure(proc);
			err = LoadNew(proc, 1, err, out HObject obj);
			HalconAPI.PostCall(proc, err);
			GC.KeepAlive(this);
			GC.KeepAlive(objectsReplace);
			return obj;
		}
	}
}
